<?
	/**
	@author: José Cláudio Medeiros de Lima<contato@claudiomedeiros.net>
	@version: 1.0a
	@date: 11/08/2009
	
	
	teste de implementacao
	
	$this->ValidationComponent
				->required(array('nome', 'telefone'))
					->required('email')
					->required('password')
				->field('email')->email()->minChars(10)
				->field('username')->unique(Model, TableField)->minChars(6)->required()
				->field('password')->equalTo('password2')->between(6,15)
		 ->isValid();
				
	Bugs conhecidos
	

*/

	class ValidationComponent extends Component{
	
		/**
		 *	Guarda os dados do formulário. Essa variável é alimentada por initialize()
		 */
		public $data;

		/**
		 *	Guarda as mensagens de erro geradas
		 */
		public $errorMessages=null;

		/**
		 *	Armazena o nome do campo atualmente em uso
		 */
		public $nowfield;

		/**
		 *	Guarda as mensagens de erro padronizadas.
		 *	Essas mensagens só serão exibidas quando não for definida uma mensagem de erro personalizada.
		 *	É possível personalizar as mensagens de erro através das seguintes palavras-chave: 
		 * 	DATA, NAME_FIELD, PARAM_FUNCTION_1 e PARAM_FUNCTION_2
		 *		DATA:					Exibe na mensagem de erro o dado digitado no formulário para esse campo específico
		 *		NAME_FIELD:			Exibe na mensagem de erro o nome do campo do formulário que gerou o erro
		 *		PARAM_FUNCTION_1:	Exibe na mensagem de erro o primeiro parâmetro da função de validação. 						
		 *								Ex.: Na função mask(), o primeiro parâmetro é a máscara que o valor do 						
		 *								campo deve ter. Nesse caso, para um campo "cpf" que chama mask("000.000.000-00"),						
		 *								a mensagem de erro receberá "000.000.000-00" em substituição a "PARAM_FUNCTION_1",						
		 *								e a mensagem seria exibida como: "cpf" precisa estar no formato "000.000.000-00"
		 *		PARAM_FUNCTION_2	Mesma função que a anterior, mas refere-se ao segundo parâmetro, nas funções que 						
		 *								o requerem, como between(), por exemplo. 
		 *		Obs.: Todas as funções de validação recebem como último parâmetro $msg, que é uma mensagem						
		 *				personalizada para aquela regra específica. Quando falamos em primeiro parâmetro, e 						
		 *				segundo parâmetro no contexto das palavras-chave PARAM_FUNCTION, não está se levando 						
		 *				em conta o parâmetro $msg.
		 */
		private $messages = array(
			'alpha'		=>	"\"NAME_FIELD\" s&oacute; aceita letras",
			'alphanum'	=>	"\"NAME_FIELD\" s&oacute; aceita letras e n&uacute;meros",
			'between'	=>	"\"NAME_FIELD\" precisa ser maior que \"PARAM_FUNCTION_1\" e menor que \"PARAM_FUNCTION_2\"",
			'cnpj'		=>	"T&iacute;tulo Eleitoral inv&aacute;lido",
			'cpf'			=>	"O valor \"DATA\" informado no campo \"NAME_FIELD\" n&atilde;o &eacute; v&aacute;lido",
			'custom'		=>	"O campo \"NAME_FIELD\" precisa estar no formato \"PARAM_FUNCTION_1\"",
			'date'		=>	"O campo \"NAME_FIELD\" informado n&atilde;o &eacute; uma data v&aacute;lida",
			'email'		=>	"O e-mail \"DATA\" n&atilde;o &eacute; v&aacute;lido",
			'equalTo'	=>	"O campo \"NAME_FIELD\" informado n&atilde;o &eacute; igual ao \"PARAM_FUNCTION_1\".",
			'inList'		=>	"O valor \"DATA\" não consta na lista de valores permitidos para o campo \"NAME_FIELD\"",
			'ipv4'		=>	"Endere&ccedil;o IPv4 inv&aacute;lido",
			'ipv6'		=>	"Ender&ccedil;eo IPv6 inv&aacute;lido",
			'mask'		=>	"\"NAME_FIELD\" precisa estar no formato \"PARAM_FUNCTION_1\"",
			'maxChars'	=>	"\"NAME_FIELD\" precisa ter menos de \"PARAM_FUNCTION_1\" caracteres",
			'maxValue'	=>	"\"NAME_FIELD\" n&atilde;o pode ser maior que \"PARAM_FUNCTION_1\"",
			'minChars'	=>	"\"NAME_FIELD\" precisa ter pelo menos \"PARAM_FUNCTION_1\" caracteres",
			'minValue'	=>	"\"NAME_FIELD\" n&atilde;o pode ser menor que \"PARAM_FUNCTION_1\"",
			'numChars'	=>	"\"NAME_FIELD\" precisa ter exatamente \"PARAM_FUNCTION_1\" caracteres",
			'number'		=>	"\"NAME_FIELD\" n&atilde;o &eacute; um n&uacute;mero",
			'pis'			=>	"N&uacute;mero do PIS/PASEP inv&aacute;lido",
			'required'	=>	"O campo \"NAME_FIELD\" &eacute; obrigat&oacute;rio",
			'text'		=>	"\"NAME_FIELD\" n&atilde;o aceita esses caracteres: PARAM_FUNCTION_1",
			'titulo'		=>	"T&iacute;tulo Eleitoral inv&aacute;lido",
			'unique'		=>	"\"DATA\" j&aacute; existe no banco de dados",
			'url'			=>	"O valor \"DATA\" informado no campo \"NAME_FIELD\" n&atilde;o &eacute; uma URL v&aacute;lida",
		);
		
		/**
		 *	
		 */
		public function initialize(&$controller){
			$this->controller = &$controller;
			$this->data = $this->controller->data;
		}
		
		/**
		 *	Verifica se aconteceu algum erro de validação
		 *	Adicionalmente, esse método já libera para uso na view a 
		 *	variável $validationErrors, que guarda todos os erros de  
		 *	validação em formato de lista não-ordenada e com uma class 'error'
		 *	
		 *	@return boolean
		 */
		public function isValid(){
			if(is_null($this->errorMessages)):
				return true;
			else:
				$this->controller->set("validationErrors", $this->getMessagesAsList());
				return false;
			endif;
		}
		
		/**
		 *	Marca os campos como obrigatórios
		 *	
		 *	@param  $fields 	os nomes dos campos que são obrigatórios. Pode ser nulo, nesse caso ele deve  estar
		 							vinculado a um campo. Pode receber os nomes dos campos obrigatórios individualmente
									ou o nome dos campos em formato de array, ou ainda um asterisco "*" caso  todos  os
									campos sejam obrigatórios.
				Ex.:
					->required("*")						- todos os campos são obrigatórios
					->required('cpf') 					- o campo 'cpf' é obrigatório
					->required(array('nome', 'cpf')) - os campos 'nome' e 'cpf' são obrigatórios
					->field('user')->required()		- o campo user é obrigatório
		 							
		 *	@return $this
		 */
		public function required($fields=null, $msg=null){
			if(is_null($fields)): //se tiver vinculado a um campo
				if($this->nowdata()==""): 
					$this->error($msg, 'required'); 
				endif;
			elseif($fields=="*"): //se todos forem obrigatórios
				foreach($this->data as $key=>$data):
					if($data==""): 
						$this->nowfield = $key;
						$this->error($msg, 'required'); 
					endif;
				endforeach;
			elseif(is_string($fields)): //se só um campo for declarado
				$this->nowfield = $fields;
				if($this->nowdata()==""): 
					$this->error($msg, 'required'); 
				endif;
			elseif(is_array($fields)): //se vários campos forem declarados em um array
				foreach($fields as $field):
					$this->nowfield = $field;
					if($this->nowdata()==""): $this->error($msg, 'required'); endif;
				endforeach;
			endif;
			
			return $this;
		}
		
		/**
		 *	Retorna o foco do encadeamento para um campo específico
		 *
		 *	@param $name O nome do campo
		 *	@return $this
		 */
		public function field($name){
			$this->nowfield = $name;
			return $this;
		}
		
		/**
		 *	function alpha()
		 *	Verifica se é uma string contendo somente texto. Qualquer outro caractere gerará um erro, inclusive caracteres acentuados.
		 *	
		 *	@version:	0.1 - 14/05/2009
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 */
		public function alpha($msg=null){
			if(eregi("([^a-z])",$this->nowdata())):	//se encontrar alguma coisa que não seja permitida
				$this->error($msg, 'alpha');
			endif;
			return $this;
		}

		/**
		 *	function alphanum()
		 *	Verifica se é uma string contendo somente caracteres alfanuméricos. Qualquer outro caractere gerará um erro, inclusive caracteres acentuados.
		 *	
		 *	@version:	0.1 - 14/05/2009
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 */
		public function alphanum($msg=null){
			if(eregi("([^a-z0-9])",$this->nowdata())):	//se encontrar alguma coisa que não seja permitida
				$this->error($msg, 'alphanum');
			endif;
			return $this;
		}

		/**
		 *	function between()
		 *	Retorna erro se o valor do campo estiver fora do intervalo definido por $min e $max
		 *
		 *	@param $min	O número mínimo do intervalo
		 *	@param $max	O número máximo do intervalo
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function between($min, $max, $msg=null){
			if(is_numeric($this->nowdata())):
				if($this->nowdata()<$min || $this->nowdata()>$max):
					$this->error($msg, 'between', $min, $max);
				endif;
			endif;
			return $this;
		}
		
		/**
		 *	function custom()
		 *	Verifica se valor informado no campo está em um formato pré-definido
		 *
		 *	@param 
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function custom($pattern, $msg=null){
			if(!eregi($pattern,$this->nowdata())):
				$this->error($msg, 'custom', $pattern);
			endif;
			return $this;
		}

		/**
		 *	function date()
		 *	@version:	0.1 - 13/05/2009
		 *	@description	Verifica se uma data é válida. Como a validação é para o Brasil, a data tem que estar no formato dd/mm/aaaa.
		 *	@param	string	nomecampo	Nome do campo
		 *	@param	string	value		A data a ser validada
		 */
		public function date($msg=null){
			$stamp = explode("/", $this->nowdata());
			if(count($stamp)==3):
				if(!checkdate($stamp[1], $stamp[0], $stamp[2])):
					$this->error($msg, 'date');
				endif;
			else:
				$this->error($msg, 'date');	
			endif;
			return $this;
		}
		
		/**
		 *	function email()
		 *	Verifica se o campo possui um endereço de e-mail válido
		 *
		 *	@param $name O nome do campo
		 *	@return $this
		 */
		public function email($msg=null){
			if (!filter_var($this->nowdata(), FILTER_VALIDATE_EMAIL)):
				$this->error($msg, 'email');
			endif;
			return $this;
		}

		/**
		 *	function equalTo()
		 *	Retorna erro se o valor do campo definido em $otherField for diferente do valor desse campo atual
		 *
		 *	@param $otherField O nome do outro campo que será comparado com esse
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function equalTo($otherField, $msg=null){
			if($this->nowdata()!=$this->data[$otherField]):
				$this->error($msg, 'equalTo', $otherField);
			endif;
			return $this;
		}
		
		/**
		 *	function inList()
		 *	Verifica se valor informado no campo pertence a uma lista de valores
		 *
		 *	@param 
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function inList($param=array(), $msg=null){
			if(empty($param)):
				$this->error("Programador, reveja sua chamada ao m&eacute;todo inList()");
			else:
				if(is_array($param)):
					if(!in_array($this->nowdata(), $param)):
						$this->error($msg, 'inList');
					endif;
				elseif(is_string($param)):
					if($this->nowdata()<>$param):
						$this->error($msg, 'inList');
					endif;
				endif;
			endif;
			return $this;
		}
		
		/**
		 *	function ip()
		 *	@version:	0.1 - 13/05/2009
		 *	@description	Valida um IPv4
		 					Esse método é um apelido para ipv4()
		 *	@param	string	nomecampo	Nome do campo
		 *	@param	string	value		IPv4 a ser validado
		 */
		public function ip($msg=null){
			$this->ipv4($msg);
			return $this;
		}

		/**
		 *	function ipv4()
		 *	@version:	0.1 - 13/05/2009
		 *	@description	Valida um IPv4
		 *	@param	string	nomecampo	Nome do campo
		 *	@param	string	value		IPv4 a ser validado
		 */
		public function ipv4($msg=null){
			if (!filter_var($this->nowdata(), FILTER_VALIDATE_IPV4)):
				$this->error($msg, 'ipv4'); 
			endif;
			return $this;
		}

		/**
		 *	function ipv6()
		 *	@version:	0.1 - 13/05/2009
		 *	@description	Valida um IPv6
		 *	@param	string	nomecampo	Nome do campo
		 *	@param	string	value		IPv6 a ser validado
		 */
		public function ipv6($msg=null){
			if (!filter_var($this->nowdata(), FILTER_VALIDATE_IPV6)):
				$this->error($msg, 'ipv6'); 
			endif;
			return $this;
		}
		
		/**
		 *	function minChars()
		 *	Verifica se o valor do campo tem um número mínimo de caracteres
		 *
		 *	@param 
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function minChars($param, $msg=null){
			if(strlen(trim($this->nowdata()))<$param):
				$this->error($msg, 'minChars', $param);
			endif;
			return $this;
		}
		
		/**
		 *	function minValue()
		 *	Compara se o valor inserido é maior ou igual ao mínimo válido para o campo
		 *
		 *	@param $min Número mínimo a ser comparado pela função
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function minValue($min, $msg=null){
			if($this->is_numeric($this->nowdata())):
				if($this->nowdata()<$min):
					$this->error($msg, 'minValue', $min);
				endif;
			endif;
			return $this;
		}
		
		/**
		 *	function mask()
		 *	Retorna erro se o valor do campo não bater com o valor da máscara definida em $mask
		 *
		 *	@param $mask	A máscara requerida para o campo. 
		 						A máscara precisa ser no estilo "(00) 0000-0000", onde os "0" 
								representarão os números digitados. Para representar um caractere, 
								usa-se "X" ou "x". Ex.: "0000-X" aceitaria algo assim: "0123-z".
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function mask($mask, $msg=null){
			$allowedSeparators = array("/", "-", ".", "(", ")", " ");
			$value = $this->nowdata();
			$lenvalue = strlen($value);
			
			if($lenvalue!=strlen($mask)):
				$this->error($msg, 'mask', $mask);
			else:
				for($i=0; $i<$lenvalue; $i++):
					if(is_numeric($value[$i]) && $mask[$i]=="0"): 	//é um número e bate com o valor da máscara
						continue;
					elseif($this->isText($value[$i]) && $mask[$i]=='x'):
						continue;
					elseif(in_array($value[$i], $allowedSeparators) && $value[$i]==$mask[$i]):
						continue;
					else:
						$this->error($msg, 'mask', $mask);
						break;
					endif;
				endfor;
			endif;
			return $this;
		}
		
		/**
		 *	function maxChars()
		 *	Verifica se o valor informado no campo tem a quantidade máxima de caracteres
		 *
		 *	@param 
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function maxChars($param, $msg=null){
			if(strlen(trim($this->nowdata()))>$param):
				$this->error($msg, 'maxChars', $param);
			endif;
			return $this;
		}
		 
		/**
		 *	function maxValue()
		 *	Compara se o valor inserido é menor ou igual que o máximo válido para o campo
		 *
		 *	@param $min Número mínimo a ser comparado pela função
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function maxValue($max, $msg=null){
			if($this->is_numeric($this->nowdata())):
				if($this->nowdata()>$max):
					$this->error($msg, 'maxValue', $max);
				endif;
			endif;
			return $this;
		}

		/**
		 *	function number()
		 *	Verifica se é um valor numérico
		 *
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function number($msg=null){
			if(!is_numeric($this->nowdata())):
				$this->error($msg, 'number');
			endif;
			return $this;
		}

		/**
		 *	function numChars()
		 *	Verifica se o valor informado no campo tem a quantidade máxima de caracteres
		 *
		 *	@param 
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function numChars($param, $msg=null){
			if(strlen(trim($this->nowdata()))==$param):
				$this->error($msg, 'numChars', $param);
			endif;
			return $this;
		}
		
		/**
		 *	function text()
		 *	@version:	0.2 - 10/08/2009
		 *	@description	Verifica se é uma string contendo somente texto, números, e os seguintes caracteres: " "(Espaço), "-" (Hífen), "." (ponto) e "_" (Underscore).
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function text($msg=null){
			if(preg_match_all("([^0-9a-zà-ú _\.-])", $this->nowdata(), $out)):
				$this->error($msg, 'text', implode(", ", array_unique($out[0])));
			endif;
			return $this;
		}

		/**
		 *	function unique()
		 *	Retorna erro se o valor do campo já existir na coluna $column do model $model
		 *
		 *	@param $model O nome do model
		 *	@param $column O nome da coluna a ser pesquisada
		 *	@param $msg Mensagem personalizada para esse campo. Caso seja null, error() roteará a mensagem para o padrão da função de validação
		 * @return $this
		 */
		public function unique($model, $column, $msg=null){
			$modelObj = ClassRegistry::init($model);
			if(count($modelObj->findBy($column, trim($this->nowdata())))<>0):
				$this->error($msg, 'unique', $model, $column);
			endif;
			return $this;
		}
		
		/**
		 *	function url()
		 *	@version:	0.2 - 09/08/2009
		 *	@description	Verifica se a url informada pertence ao padrão definido pela RFC
		 *						Para usar, pode ser de 5 formas diferentes
		 *						->url()	Assim valida urls normais e com a mensagem de erro padrão
		 *						->url('host') Valida urls normais com a mensagem de erro padrão
		 *						->url('path') Valida urls com um PATH existente e com mensagem de erro padrão
		 *						->url(null, 'mensagem de erro personalizada') Valida urls normais e com a mensagem de erro personalizada
		 *						->url('mensagem de erro') valida urls normais e uma mensagem de erro personalizada. 
		 *														Nesse caso, como a mensagem de erro informada não é nenhum dos
		 *														3 valores possíveis para o primeiro parâmetro, então já se 
		 *														entende que está definindo a mensagem padrão
		 *	
		 *	@param	string	$nomecampo	Nome do campo
		 *	@param	string	$value		Valor a ser validado
		 *	@param	string	$parametro_rule		Segundo parâmetro da regra de validação. Flag opcional que pode receber 1 parâmetro com três valores possíveis:
		 										host, query e path, sendo host o padrão. Conforme explicado a seguir
		 		- Sobre filter_var
				para a validação de url, filter_var pode receber 4 tipos de flags como terceiro parâmetro:
					- FILTER_FLAG_SCHEME_REQUIRED	: Validará URLs de acordo com o RFC. Ex.: http://www.site.com, http://site.com e http://localhost
					- FILTER_FLAG_HOST_REQUIRED		: Validará URLs do tipo acima.
					- FILTER_FLAG_PATH_REQUIRED		: Só validará URLs que contenham paths no endereço. Ex: http://www.site.com/path. Não valida http://localhost/foo.
					- FILTER_FLAG_QUERY_REQUIRED	: Só validará URLs que contenham query strings. Ex. http://www.site.com?id=1, http://localhost/?id=1
		 */
		public function url($urlType = null, $msg = null){
			$flags = array(
				'query'=>FILTER_FLAG_QUERY_REQUIRED,
				'path'=>FILTER_FLAG_PATH_REQUIRED,
				'host'=>FILTER_FLAG_HOST_REQUIRED
			);
			$urlType = is_null($urlType) ? 'host' : $urlType;
			if(!in_array($urlType, array_keys($flags))):
				$msg = $urlType;
				$urlType = 'host';
			endif;
			if (!filter_var($this->nowdata(), FILTER_VALIDATE_URL, $flags[$urlType])):
				$this->error($msg, 'url');
			endif;
			return $this;
		}

		
		
		
		/***************************************************************************************************************************
																métodos experimentais	- Início																	*/
		

		/**
		 *	function titulo()
		 *	@version:	0.2 - 13/05/2009
		 *	@description	Valida um título eleitoral informado, verificando se o dígito verificador é válido, e, 
		 					opcionalmente, se pertence a um estado determinado
		 *	@param	string	nomecampo	Nome do campo
		 *	@param	string	titulo		Número do título
		 *	@param	string	sigla_uf	Estado da federação. Se não pertencer a esse estado, retornará false. Se o estado não existir, retorna false
		 *	@return	Bool				Retorna verdadeiro ou falso, caso o número do título seja válido ou não.
		 ***	
		 *	FORMA DE CÁLCULO
		 *	- Para o número 19408971686, as 8 primeiras posições representam o título, as posições 10 e 11 representam o código da UF, 
		 *	e as posições 12 e 13 representam o dígito verificador.
		 *	- Para calcular o primeiro dígito, pegamos os 8 primeiros dígitos e os multiplicamos por 2, 3, 4... até 9, começando do primeiro
		 *	dígito até o último. Depois somamos os resultados, e o total será dividido por 11. O RESTO dessa divisão será o primeiro DV.
		 *	- Para o cálculo do segundo DV, pegamos os algarismos das posições 10 e 11, referentes ao UF e o caractere 12, que é o primeiro DV
		 *	já calculado. Agora multiplicamos pelos algarismos 7, 8 e 9, respectivamente, e somamos seus resultados. O total será dividido por
		 *	11 e o segundo DV será o resto da divisão.
		 *	TABELA DE UFs
			$arr_uf = array('01'=> 'SP','02'=> 'MG','03'=> 'RJ','04'=> 'RS','05'=> 'BA','06'=> 'PR','07'=> 'CE',
							'08'=> 'PE','09'=> 'SC','10'=> 'GO','11'=> 'MA','12'=> 'PB','13'=> 'PA','14'=> 'ES',
							'15'=> 'PI','16'=> 'RN','17'=> 'AL','18'=> 'MT','19'=> 'MS','20'=> 'DF','21'=> 'SE',
							'22'=> 'AM','23'=> 'RO','24'=> 'AC','25'=> 'AP','26'=> 'RR','27'=> 'TO','28'=> 'EX');
		 */
		public function titulo($sigla_uf=null, $msg=null){
			//Só permite números
			if(eregi("([^0-9]+)",$this->nowdata())):
				$this->error($msg, 'titulo'); 
			else:

				//	precisa ter 12 caracteres numéricos. retira tudo q nao for número e adiciona zeros à esquerda.
				$titulo = str_pad($this->nowdata(),12,"0",STR_PAD_LEFT);
			
				$tit = substr($titulo,0,8);
				$num_uf =  substr($titulo,8,2);
				$dv =  substr($titulo,10,2);
				$ignore_list = array('000000000000');
				
				if(in_array($titulo, $ignore_list)): $error=4; endif;
				//array dos estados
				$arr_uf = array('01'=> 'SP','02'=> 'MG','03'=> 'RJ','04'=> 'RS','05'=> 'BA','06'=> 'PR','07'=> 'CE',
								'08'=> 'PE','09'=> 'SC','10'=> 'GO','11'=> 'MA','12'=> 'PB','13'=> 'PA','14'=> 'ES',
								'15'=> 'PI','16'=> 'RN','17'=> 'AL','18'=> 'MT','19'=> 'MS','20'=> 'DF','21'=> 'SE',
								'22'=> 'AM','23'=> 'RO','24'=> 'AC','25'=> 'AP','26'=> 'RR','27'=> 'TO','28'=> 'EX');
				
				//verifica se informou o estado
				if(!is_null($sigla_uf)):
					if(!in_array($sigla_uf,$arr_uf)): $error=1; endif;	//se o estado requerido pertence à tabela de valores
					if($sigla_uf <> $arr_uf[$num_uf]): $error=2;  endif; //se o estado requerido é igual ao estado 
																													//	informado pelo usuário,
				endif;										// obrigando ao usuário só informar um título de um estado específico
				
				//se o num_uf informado no título for maior que 28 entao é inválido
				if($num_uf>28): $error=3; endif;
				//1 dv
				for($i=0; $i<8; $i++):
					$soma1 += $tit[$i] * ($i+2);
				endfor;
				//2 dv
				$soma2 = $num_uf[0] * 7 + $num_uf[1] * 8 + ($soma1%11)*9;
			
				if(($soma1%11).($soma2%11) != $dv): 
					$error=5;
				endif;
				
				if($error>0):
					$this->error($msg, 'titulo'); 
				endif;
			endif;
			return $this;
		}

		/**
		* function pis()
		*	@version:	0.3 - 18/05/2009
		*	@description	Valida um PIS (Programa de Integração Social)
		*	@param	string	nomecampo	Nome do campo
		*	@param	string	$pis	Nome do campo
		*	Versão 0.2 aceitava letras e outros caracteres não permitidos.
		*/
		public function pis($msg=null){
			//permite pontos e traços, mas não deve permitir outras coisas
			if(eregi("([^0-9\.-]+)",$this->nowdata())):
				$this->error($msg, 'pis'); 
			else:
				//elimina tudo q nao for números e acrescenta zeros à esquerda
				$pis = str_pad(eregi_replace("([^0-9])","",$this->nowdata()),11,"0",STR_PAD_LEFT);
				$dv = substr($pis,-1,1);
				//sequencia de números a serem calculados
				$seqcalc = "3298765432";
				
				$soma = 0;
		
				for($i=0; $i<10; $i++):
					$soma+=$pis[$i] * $seqcalc[$i];
				endfor;
		
				$dv1 = (($soma%11)<2) ? 0 : (11-($soma%11));
		
				if($dv1 != $dv): 
					$this->error($msg, 'pis');
				endif;
			endif;
			return $this;
		}
		
		/**
		 *	function cpf()
		 *	@version:	0.3 - 18/05/2009
		 *	@description	Valida um CPF
		 *	@param	string	nomecampo	Nome do campo
		 *	@param	string	$value	CPF que será validado
		 *	Versão 0.2 aceitava letras e outros caracteres não permitidos
		 */
		public function cpf($msg=null) { 
			//permite pontos e traços, mas não deve permitir outras coisas
			if(eregi("([^0-9\.-]+)",$this->nowdata())): 
				$this->error($msg, 'cpf');
			else:
				//substitui, para fins de validação, os pontos e os traços
				$value = eregi_replace("([^0-9])","",$this->nowdata());
				$cpf = substr($value, 0, 9);
				$dv = substr($value,9,2);
				
				for($i=0; $i<=9;$i++): 
					$ignore_list[] = str_repeat($i,11); //gerando ignore list
					$soma+= $cpf[$i] * (10-$i);
					$soma2+= $cpf[$i] * (11-$i);
				endfor;
				
				if(in_array($value, $ignore_list)):
					$erro=1;
				endif;
				
				$dv1 = (($soma%11)<=1) ? 0 : (11 - ($soma%11));
				$soma2= ($soma2 + $dv[0]*2)%11;
				$dv2 = (($soma2%11)<=1) ? 0 : (11 - ($soma2%11));
				
				if($dv1.$dv2 != $dv[0].$dv[1]):
					$erro=2;
				endif;
				
				if($erro<>0):
					$this->error($msg, 'cpf');
				endif;
			endif;
			return $this;
		}

		/**
		 *	function cnpj()
		 *	@version:	0.2 - 18/05/2009
		 *	@description	Valida um CNPJ
		 *	@param	string	nomecampo	Nome do campo
		 *	@param	string	$value	CNPJ que será validado
		 *	Versão 0.1 aceitava letras e outros caracteres não permitidos
		 */
		public function cnpj($msg=null){
			//permite pontos, barras e traços, mas não deve permitir outras coisas
			if(eregi("([^0-9\.\/-]+)",$this->nowdata())): 
				$this->erro($msg, 'cnpj'); 
			else:
				//elimina tudo que não for números e acrescenta zeros à esquerda
				$cnpj = str_pad(eregi_replace("([^0-9])","",$this->nowdata()),14,"0",STR_PAD_LEFT);
				$dv = substr($this->nowdata(),-2,2);
				$seqcalc1 = "543298765432";
				$seqcalc2 = "6543298765432";
				
				$soma1 = $soma2 = 0;
				//faz as multiplicações
				for($i=0; $i<12; $i++):
					$soma1+=$cnpj[$i] * $seqcalc1[$i];
					$soma2+=$cnpj[$i] * $seqcalc2[$i];
				endfor;
				
				$dv1 = (($soma1%11)<2) ? 0 : (11-($soma1%11));
		
				$soma2 += $dv1*2;
				$dv2 = (($soma2%11)<2) ? 0 : (11-($soma2%11));
		
				if($dv1.$dv2 != $dv): $this->error($msg, 'cnpj'); endif;
			endif;
			return $this;
		}		
		
		/*														métodos experimentais	- Fim
		*****************************************************************************************************************************/
		
		/**
		 *	Retorna as mensagens de erro em forma de array
		 *	
		 *	@return array
		 */
		public function getMessages(){
			return $this->errorMessages;
		}

		/**
		 *	Retorna as mensagens de erro em forma de lista <li> e já com a classe css "error"
		 *	
		 *	@param $class o nome da classe css que será aplicada ao <ul>. O padrão é a classe 'error'
		 *	@return string html já pronto para imprimir na view. Esse valor 
		 						já ficará disponível automaticamente para a view 
								através da variável "validationErrors"
		 */
		public function getMessagesAsList($class="error"){
			if(!is_null($this->errorMessages)):
				$html = "<ul class={$class}>\n\t<li>";
				$html.=implode("</li><li>",$this->errorMessages);
				$html.="</li>\n</ul>";
				return $html;
			endif;
		}
		
		/**
		 * Faz o roteamento das mensagens de erro que a validação gerará. 
		 *	Se não especificar uma mensagem específica, será usada a 
		 *	mensagem padrão da função
		 *	
		 *	@param $msg recebe uma mensagem personalizada para o campo específico
		 *	@param $function recebe o nome da função. caso nao seja dada nenhuma 
		 *							mensagem específica, será usada a mensagem padrão para o campo.
		 *	@param $first_param é o primeiro parâmetro da função de validação
		 *	@param $second_param é o segundo parâmetro da função de validação
		 *	@return boolean
		 */
		public function error($msg=null, $function=null, $first_param=null, $second_param=null){
			if(is_null($msg) && is_null($function)):
				$this->errorMessages[] = "Programador, reveja sua chamada à função error()";
				return false;
			elseif(!is_null($msg)):
				$this->errorMessages[] = str_replace("DATA",$this->nowdata(),$msg);
				return true;
			elseif(!is_null($function)):
				$in = array("DATA", "NAME_FIELD", "PARAM_FUNCTION_1", "PARAM_FUNCTION_2");
				$out= array($this->nowdata(), $this->nowfield, $first_param, $second_param);
				
				$this->errorMessages[] = str_replace($in,$out,$this->messages[$function]);
				return true;
			endif;
		}
		
		/**
		 *	Retorna o valor inserido no campo que está sendo processado no momento
		 *	
		 *	@return string
		 */
		private function nowdata(){
			return $this->data[$this->nowfield];
		}
		
		/**
		 *	Retorna se o texto é ou não texto
		 *	
		 *	@param $text o texto a ser verificado
		 *	@return bool
		 */
		private function isText($text){
			if(eregi("([^a-zà-ú])",$text)):
				return false;
			else:
				return true;
			endif;
		}
		
	} 
?>